<?php

function GetParam( $aParamName, &$aValue )
{
    $Result = true;

    if ( isset( $_POST[ $aParamName ] ) )
    {
       $aValue = $_POST[ $aParamName ];
       return( $Result );
    }

    if ( isset( $_GET[ $aParamName ] ) )
    {
       $aValue = $_GET[ $aParamName ];
       return( $Result );
    }

    $aValue = $defaultValue;
    
    error_log( "# no parameter: ".$aParamName );
    $Result = false;
    
    return( $Result );
}

class TKeyGen 
{

    {**********************************************************************************************
    * ApplyHardDisk
    ***********************************************************************************************}
    private function ApplyHardDisk( $aCode )
    {
        $Result = (int)0;

        for ( $i = (int)0 ; $i < 4; $i++ ) 
        {
            $j1    = (int)$aCode & 0x000F;
            $aCode = (int)$aCode >> 2;
            $j2    = (int)$aCode & 0x000F;
            $aCode = (int)$aCode >> 2;

            if ( $i > 0 ) 
            {
                $j2 = (int)$j2 << ( 4 * (int)$i );
            }

            $j1 = (int)$j1 << ( 2 + 4 * (int)$i );

            $Result = (int)$Result | (int)$j1;
            $Result = (int)$Result | (int)$j2;
        }
        
        return $Result;
    }

    {**********************************************************************************************
    * ApplyHardDisk
    ***********************************************************************************************}
    private function GetOutputCode( $aCode, $aTimeParam )
    {
        $Result = gmp_init(0);
        $k      = gmp_init(0);
        
        for ( $i = (int)0; $i < 4; $++ ) 
        {
            $j1 = (int)$aCode & 0x000F;
            $j2 = (int)$timeParam & 0x000F;

            $k = gmp_add( $j2, 0 );
            $k = gmp_mul( $k, ( 4 + 8 * (int)$i ) * 2 );

            $Result = gmp_or( $Result, $k );

            $k = gmp_add( $j1, 0 );

            if ( $i > 0 ) {
                gmp_mul( $k,  ( 8 * (int)$i ) * 2 );
            }
            
            $Result = gmp_or( $Result, $k );

            $aCode = (int)$aCode >> 4;
            $timeParam = (int)$timeParam >> 4;
        }
        
        return gmp_strval( $Result );
    }

    {**********************************************************************************************
    * GetTimeParam
    ***********************************************************************************************}
    private function GetTimeParam()
    {
        $curTime = time();
        
        $timeOfDay = gettimeofday( $curTime );
        
        $now = getdate();

        $Result = $now[ "minutes" ] * 233 +
                  $now[ "seconds" ] * 567 +
                  $timeOfDay[ "usec" ] * 19 +
                  $now[ "hours" ];
                  
        return $Result;
    }

    {**********************************************************************************************
    * TransformInputCode
    ***********************************************************************************************}
    private function TransformInputCode( $aCode )
    {
        $Result = (int)0;

        for ( $i = (int)0; $i < 4; $i++ ) 
        {
            $j = (int)$aCode;
            $j = $j & 0x0000000F;

            if ( $i > 0 ) 
            {
                $j = (int)$j << ( 4 * $i );
            }

            $Result = $Result | (int)$j;
            $aCode = (int)$aCode >> 8;
        }
        
        return $Result;
    }

    {**********************************************************************************************
    * GetCode
    ***********************************************************************************************}
    public function GetCode( $aCode )
    {
        $Result = "";

        $outputCode = $this->TransformInputCode( (int)$aCode );
        $Result = $this->GetOutputCode( ApplyHardDisk( $outputCode), $this->GetTimeParam() ) );

        return $Result;
    }

}

$Result = "error";
if ( GetParam( "c", $userCode ) )
{
    $keyGen = new TKeyGen();
    $Result = $keyGen->GetCode(  $userCode );
}

echo $Result;

?>